using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using Xeml.Document.EnvironmentalOntology;
using Xeml.Document;
using Xeml.Document.Contracts;

namespace Xid.Controls.ParameterEditCtrls
{
    public partial class ContextEditCtrl : UserControl
    {
        #region Fields
        private EditMode edtMode;
        private string context;
        private IDynamicOntologyTerm paramSpec;
        private string nsAlias;

        private Cycle _defCycle;
        private DynamicValue _defValue;
        private DynamicValueBase _currentValue;

        private TimeSpan targetTime;
        private DynamicTerm param;
        private Color contextColor;
        #endregion

        #region Properties
        /// <summary>
        /// The time point to view/edit.
        /// </summary>
        public TimeSpan TargetTime
        {
            get { return targetTime; }
            set
            {
                targetTime = value;
                if (this._currentValue != null)
                {
                    this._currentValue.Time = value;
                    //this.kryptonHeaderGroup1.ValuesSecondary.Heading = this._currentValue.Time.ToString();
                }
                else
                    this.kryptonHeaderGroup1.ValuesSecondary.Heading = this.targetTime.ToString();
            }
        }

        /// <summary>
        /// Gets and sets the current parameter
        /// </summary>
        public DynamicTerm Parameter
        {
            get { return param; }
            set
            {
                if (param != null)
                {
                    param.Values.Cleared -= new EventHandler(OnValuesCleared);
                }
                param = value;
                if (param != null)
                {
                    param.Values.Cleared += new EventHandler(OnValuesCleared);
                }
            }
        }
        #endregion

        public ContextEditCtrl()
        {

            InitializeComponent();
            buttonSpecHeaderGroupDrop.Visible = false;
            //this.cycleEditorCtrl1.GrowthOrShrink += new EventHandler(cycleEditorCtrl1_GrowthOrShrink);
            this.radioButtonCycle.CheckedChanged += new EventHandler(OnEditModeChanged);
            this.radioButtonValue.CheckedChanged += new EventHandler(OnEditModeChanged);

        }


        void OnEditModeChanged(object sender, EventArgs e)
        {


            if (radioButtonCycle.Checked && !(_currentValue is Cycle) && _currentValue != null) //switch to cycle
            {
                this._defValue = _currentValue as DynamicValue;
                this.param.Values.Remove(_currentValue);
                Cycle c = null;
                if (_defCycle != null)
                {
                    c = new Cycle(_defCycle);
                    c.Time = targetTime;
                    this.param.Values.Add(c);
                }
                SetupValue(c, false);

            }


            if (radioButtonValue.Checked && !(_currentValue is DynamicValue) && _currentValue != null)
            {

                this._defCycle = _currentValue as Cycle;
                this.param.Values.Remove(_currentValue);
                DynamicValue v = null;
                if (_defValue != null)
                {
                    v = new DynamicValue(_defValue);
                    v.Time = targetTime;
                    this.param.Values.Add(v);
                }
                SetupValue(v, false);
            }

            // SwitchValueEntryMode();


        }



      
        #region Methods
        /// <summary>
        /// The initialize method for this control.
        /// </summary>
        /// <param name="pspec"></param>
        /// <param name="pcs"></param>
        /// <param name="nsAlias"></param>
        /// <param name="c"></param>
        public void SetupSpec(IDynamicOntologyTerm pspec, string context, string nsAlias, Color c)
        {
            this.comboBoxValue.DataBindings.Clear();
            this.numericUpDownValue.DataBindings.Clear();
            this.comboBoxUnit.DataBindings.Clear();


            this.context = context;
            this.paramSpec = pspec;
            this.nsAlias = nsAlias;
            this.contextColor = c;
            FormatMe();
            SetupSpec();
            CalculateDefaultVals();
            //SetupValue();
        }

        /// <summary>
        /// Sets the controls to meet the parameter/context spec.
        /// </summary>
        private void SetupSpec()
        {
            if (!string.IsNullOrEmpty(this.context) && this.paramSpec != null)
            {
                this.kryptonHeaderGroup1.ValuesPrimary.Heading = this.context;
                comboBoxUnit.DataSource = paramSpec.ListUnits(this.context);
                comboBoxUnit.DisplayMember = "Key";
                comboBoxUnit.ValueMember = "Value";
                SetValueEdit();
            }
        }


        private void SwitchValueEntryMode()
        {
            if (this._currentValue == null)
            {
                cycleEditorCtrl1.Visible = false;
                comboBoxValue.Enabled = false;
                numericUpDownValue.Enabled = false;

                this.comboBoxUnit.Enabled = false;
                this.radioButtonCycle.Enabled = false;
                this.radioButtonValue.Enabled = false;
            }
            else if (this._currentValue is DynamicValue)
            {
                cycleEditorCtrl1.Visible = false;
                comboBoxValue.Enabled = true;
                numericUpDownValue.Enabled = true;

                this.comboBoxUnit.Enabled = this.paramSpec.HasDefaultUnit(this.context);
                this.radioButtonCycle.Enabled = true;
                this.radioButtonValue.Enabled = true;
            }
            else if (this._currentValue is Cycle)
            {
                cycleEditorCtrl1.Visible = true;
                comboBoxValue.Enabled = false;
                numericUpDownValue.Enabled = false;

                this.comboBoxUnit.Enabled = this.paramSpec.HasDefaultUnit(this.context);
                this.radioButtonCycle.Enabled = true;
                this.radioButtonValue.Enabled = true;
            }
            // OnResize(new EventArgs());  //Because of the kryptongroupbox-autoresize bug
        }
        /// <summary>
        /// Sets the current value for editing.
        /// </summary>
        /// <param name="v"></param>
        private void SetupValue(DynamicValueBase v, bool changeCheckedState)
        {

            if (this._currentValue != null)
            {

                this._currentValue.PropertyChanged -= new PropertyChangedEventHandler(_currentValue_PropertyChanged);
            }
            this._currentValue = v;


            SetSecondaryHeader();
            SwitchValueEntryMode();
            //if (this.val != null)
            //    this.targetTime = v.Time;
            if (this._currentValue == null)
            {
                this.buttonSpecHeaderGroupDrop.Visible = false;
                this.buttonSpecHeaderGroupPopulate.Visible = true;
                if (changeCheckedState)
                    radioButtonValue.Checked = true;
                //this.kryptonHeaderGroup1.ValuesSecondary.Heading = this.targetTime.ToString();
                //this.kryptonHeaderGroup1.ValuesSecondary.Description = "null";

                //this.comboBoxUnit.Enabled = false;
                //this.comboBoxValue.Enabled = false;
                //this.numericUpDownValue.Enabled = false;
                //this.radioButtonCycle.Enabled = false;
                //this.radioButtonValue.Enabled = false;
            }
            else
            {
                this._currentValue.PropertyChanged += new PropertyChangedEventHandler(_currentValue_PropertyChanged);
                this.buttonSpecHeaderGroupDrop.Visible = true;
                this.buttonSpecHeaderGroupPopulate.Visible = false;

                this.comboBoxValue.DataBindings.Clear();
                this.numericUpDownValue.DataBindings.Clear();
                this.comboBoxUnit.DataBindings.Clear();
                this.comboBoxUnit.DataBindings.Add("SelectedValue", _currentValue, "Unit", true, DataSourceUpdateMode.OnPropertyChanged);
                if (this._currentValue is DynamicValue)
                {
                    //this.radioButtonCycle.CheckedChanged -= new EventHandler(OnEditModeChanged);
                    //this.radioButtonValue.CheckedChanged -= new EventHandler(OnEditModeChanged);
                    if (changeCheckedState)
                        radioButtonValue.Checked = true;

                    //this.radioButtonCycle.CheckedChanged += new EventHandler(OnEditModeChanged);
                    //this.radioButtonValue.CheckedChanged += new EventHandler(OnEditModeChanged);



                    switch (this.edtMode)
                    {
                        case EditMode.ComboValue:
                            {
                                this.comboBoxValue.DataBindings.Add("Text", _currentValue, "Val", true, DataSourceUpdateMode.OnPropertyChanged);
                                //this.comboBoxValue.Text = ((Value)this._currentValue).Val;
                                break;
                            }
                        case EditMode.ComboListValue:
                            {
                                this.comboBoxValue.DataBindings.Add("SelectedValue", _currentValue, "Val", true, DataSourceUpdateMode.OnPropertyChanged);
                                // this.comboBoxValue.SelectedValue = ((Value)this._currentValue).Val;
                                break;
                            }
                        case EditMode.NumericValue:
                            {
                                this.numericUpDownValue.DataBindings.Add("Value", _currentValue, "DoubleValue", true, DataSourceUpdateMode.OnPropertyChanged);
                                //this.numericUpDownValue.Value = (decimal)((Value)this._currentValue).DoubleValue;
                                break;
                            }
                        case EditMode.BooleanValue:
                            {
                              //  this.checkBox.DataBindings.Add("Checked", _currentValue, "BooleanValue", true, DataSourceUpdateMode.OnPropertyChanged);
                                this.comboBoxValue.DataBindings.Add("SelectedValue", _currentValue, "BooleanValue", true, DataSourceUpdateMode.OnPropertyChanged);
                                
                                //this.numericUpDownValue.Value = (decimal)((Value)this._currentValue).DoubleValue;
                                break;
                            }

                        default:
                            break;
                    }
                }
                else if (this._currentValue is Cycle)
                {



                    if (changeCheckedState)
                        radioButtonCycle.Checked = true;


                    this.cycleEditorCtrl1.ParameterSpec = this.paramSpec;
                    this.cycleEditorCtrl1.Context = this.context;
                    this.cycleEditorCtrl1.SetupCycle(this._currentValue as Cycle);

                }

                //this.comboBoxUnit.Enabled = true;
                //this.comboBoxValue.Enabled = true;
                //this.numericUpDownValue.Enabled = true;
                //this.radioButtonCycle.Enabled = true && this.paramSpec.AllowCycling;
                //this.radioButtonValue.Enabled = true;


            }


            FormatMe();
        }

        void _currentValue_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            SetSecondaryHeader();
            if (e.PropertyName == "Time" && ValueTimeChanged != null)
            {

            }
        }



        private void SetSecondaryHeader()
        {
            if (_currentValue != null)
            {
                this.kryptonHeaderGroup1.ValuesSecondary.Heading = this._currentValue.Time.ToString();// +" " + 
                this.kryptonHeaderGroup1.ValuesSecondary.Description = (string)this._currentValue;
            }
            else
            {
                this.kryptonHeaderGroup1.ValuesSecondary.Heading = this.targetTime.ToString();// +" " + 
                this.kryptonHeaderGroup1.ValuesSecondary.Description = "null";
            }
        }

        /// <summary>
        /// Navigates to a specific time point.
        /// </summary>
        /// <param name="ts"></param>
        public void NavigateTo(TimeSpan ts)
        {
            this.targetTime = ts;
            if (this.paramSpec != null)
            {
                this._defValue.Time = ts;
                this._defCycle.Time = ts;
            }
            if (this.param == null)
            {
                SetupValue(null, true);
                return;
            }
            DynamicValueBase vb = this.param.ValueBy(this.context).Find(delegate(DynamicValueBase x) { return x.Time == ts; });
            SetupValue(vb, true);

        }


        /// <summary>
        /// Sets the edit mode in respect to the parameter/context specification
        /// </summary>
        private void SetValueEdit()
        {

            if (paramSpec.GetEnums(this.context).Count > 0)
            {
                this.edtMode = EditMode.ComboListValue;
                comboBoxValue.Visible = true;
                numericUpDownValue.Visible = false;
                comboBoxValue.DropDownStyle = ComboBoxStyle.DropDownList;
                comboBoxValue.DataSource = paramSpec.GetEnums(this.context);
                comboBoxValue.DisplayMember = "Key";
                comboBoxValue.ValueMember = "Value";
                return;
            }
            if (paramSpec.GetDataType(this.context) == VariableDataTypes.Number)
            {
                this.edtMode = EditMode.NumericValue;
                comboBoxValue.Visible = false;
                numericUpDownValue.Visible = true;
                numericUpDownValue.DecimalPlaces = 2;
                decimal? mi = paramSpec.GetMin(this.context);
                decimal? mx = paramSpec.GetMax(this.context);
                if (mi != null)
                    numericUpDownValue.Minimum = (decimal)mi;
                if (mx != null)
                    numericUpDownValue.Maximum = (decimal)mx;
            }
            if (paramSpec.GetDataType(this.context) == VariableDataTypes.Bool)
            {
                this.edtMode = EditMode.BooleanValue;
                //BindingList<bool> bl = new BindingList<bool>();

                List<KeyValuePair<bool, bool>> bl = new List<KeyValuePair<bool, bool>>();
                
                bl.Add( new KeyValuePair<bool,bool>(true, true ));
                bl.Add(new KeyValuePair<bool, bool>(false, false));

                comboBoxValue.Visible = true;
                numericUpDownValue.Visible = false;
                comboBoxValue.DropDownStyle = ComboBoxStyle.DropDownList;
                comboBoxValue.DataSource = bl;
                comboBoxValue.DisplayMember = "Key";
                comboBoxValue.ValueMember = "Value";
                
       
      
            }

            if (paramSpec.GetDataType(this.context) == VariableDataTypes.Text)
            {
                this.edtMode = EditMode.ComboValue;
                //BindingList<bool> bl = new BindingList<bool>();
                //bl.Add(true);
                //bl.Add(false);
                comboBoxValue.Visible = true;
                numericUpDownValue.Visible = false;
                comboBoxValue.DropDownStyle = ComboBoxStyle.DropDown;
                //comboBoxValue.DataSource = bl;

            }
        }

        /// <summary>
        /// Makes color settings and assigns strings.
        /// </summary>
        private void FormatMe()
        {
            this.kryptonHeaderGroup1.ValuesPrimary.Heading = this.context;

            if (this._currentValue != null)
            {
                this.kryptonHeaderGroup1.StateCommon.HeaderPrimary.Back.Color2 = contextColor;
                this.kryptonHeaderGroup1.StateCommon.HeaderSecondary.Back.Color2 = contextColor;
                this.kryptonHeaderGroup1.StateCommon.HeaderPrimary.Content.ShortText.Color1 = Color.White;
                this.kryptonHeaderGroup1.StateCommon.HeaderSecondary.Content.ShortText.Color1 = Color.White;
                this.kryptonHeaderGroup1.StateCommon.HeaderSecondary.Content.LongText.Color1 = Color.White;
            }
            else
            {
                this.kryptonHeaderGroup1.StateCommon.HeaderPrimary.Back.Color2 = Color.Gray;
                this.kryptonHeaderGroup1.StateCommon.HeaderSecondary.Back.Color2 = Color.Gray;
                this.kryptonHeaderGroup1.StateCommon.HeaderPrimary.Content.ShortText.Color1 = Color.Silver;
                this.kryptonHeaderGroup1.StateCommon.HeaderSecondary.Content.ShortText.Color1 = Color.Silver;
                this.kryptonHeaderGroup1.StateCommon.HeaderSecondary.Content.LongText.Color1 = Color.Silver;
            }
        }

        /// <summary>
        /// Populates a new parameter according to the current spec.
        /// </summary>
        private void PopulateParameter()
        {
            this.param = (DynamicTerm)paramSpec.EmitDefaultObject(true);
            this.param.Values.Clear();
        }

        /// <summary>
        /// Populates a value according to the current spec.
        /// </summary>
        private void Populate()
        {
            if (!string.IsNullOrEmpty(this.context))
            {
                bool raiseEvent = false;
                if (this.param == null)
                {
                    PopulateParameter();
                    raiseEvent = true;
                }
                if (_defCycle != null && this.paramSpec.HasDefaultCycle(this.context))
                {
                    Cycle c = new Cycle(_defCycle);
                    c.Time = this.targetTime;
                    this.param.Values.Add(c);
                    SetupValue(c, true);
                }
                else if (_defValue != null)
                {
                    DynamicValue v = new DynamicValue(_defValue);
                    v.Time = this.targetTime;
                    this.param.Values.Add(v);
                    SetupValue(v, true);
                }

                if (raiseEvent && this.ParameterPopulated != null)
                    ParameterPopulated(this, new EventArgs());
            }
        }


        private void CalculateDefaultVals()
        {
            if (!string.IsNullOrEmpty(this.context))
            {


                if (paramSpec.HasDefaultValue(this.context))
                {
                    _defValue = paramSpec.DefaultValue(this.context, targetTime);
                    // _defValue.Context = this.paramContextSpec.Name;
                    if (this._defCycle == null)
                    {
                        _defCycle = new Cycle();
                        _defCycle.Context = this.context;
                        _defCycle.Time = this.targetTime;
                        _defCycle.Values.Add(new DynamicValue(TimeSpan.FromHours(12), ((DynamicValue)this.paramSpec.DefaultValue(this.context)).Val));
                    }

                }
                else
                {
                    _defValue = new DynamicValue(this.targetTime, "");
                    _defValue.Context = this.context;
                    switch (this.paramSpec.GetDataType(this.context))
                    {
                        case VariableDataTypes.Bool:
                            {
                                _defValue.BooleanValue = true;
                                break;
                            }
                        case VariableDataTypes.Date:
                            break;
                        case VariableDataTypes.Number:
                            {
                                _defValue.DoubleValue = 0;
                                break;
                            }
                        case VariableDataTypes.Text:
                            {
                                _defValue.Val = "";
                                break;
                            }
                        default:
                            break;
                    }
                    //if (this._defCycle == null)
                    //{
                    //    _defCycle = new Cycle();
                    //    _defCycle.Context = this.paramContextSpec.Name;
                    //    _defCycle.Time = this.targetTime;
                    //    _defCycle.Values.Add(new Value(TimeSpan.FromHours(12), _defValue.Val));
                    //}

                }

                if (paramSpec.HasDefaultCycle(this.context))
                {
                    _defCycle = paramSpec.DefaultCycle(this.context, targetTime);
                    //_defCycle.Context = this.paramContextSpec.Name;
                    //_defCycle.Time = this.targetTime;
                    //foreach (KeyValuePair<TimeSpan, string> kvp in this.paramContextSpec.DefaultCycle)
                    //{
                    //    _defCycle.Values.Add(new Value(kvp.Key, kvp.Value));
                    //}

                }
                else
                {
                    _defCycle = new Cycle();
                    _defCycle.Context = this.context;
                    _defCycle.Time = this.targetTime;
                    _defCycle.Values.Add(new DynamicValue(TimeSpan.FromHours(12), _defValue.Val));
                }

                if (paramSpec.HasDefaultUnit(this.context))
                {

                    _defValue.Unit = paramSpec.DefaultUnitSymbol(this.context);
                    _defCycle.Unit = paramSpec.DefaultUnitSymbol(this.context);
                }
            }
        }

        /// <summary>
        /// Drops the curretn value.
        /// </summary>
        public void DropValue()
        {
            if (this.param != null)
            {
                this.param.Values.Remove(this._currentValue);
                if (this.param.Values.Count == 0)
                {
                    if (ParameterDePopulated != null)
                        ParameterDePopulated(this, new EventArgs());
                }
            }
            SetupValue(null, true);
        }
        #endregion

        #region Eventhandler
        /// <summary>
        /// Eventhandler for the populate command.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnPopulate_Click(object sender, EventArgs e)
        {
            Populate();
        }

        /// <summary>
        /// Eventhandler for the drop command.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnDrop_Click(object sender, EventArgs e)
        {
            DropValue();
        }

        /// <summary>
        /// Eventhandler for the values cleared event.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void OnValuesCleared(object sender, EventArgs e)
        {
            this.targetTime = TimeSpan.Zero;
            SetupValue(null, true);
        }
        #endregion

        #region Events

        public event EventHandler ParameterPopulated;
        public event EventHandler ParameterDePopulated;
        public event EventHandler ValueTimeChanged;
        #endregion




    }

    public enum EditMode
    {
        ComboValue,
        ComboListValue,
        NumericValue,
        BooleanValue
    }
}
